package com.cynteka.cyfoman.ui;

import com.cynteka.cyfoman.core.*;
import com.cynteka.cyfoman.core.config.*;
import com.cynteka.cyfoman.core.mail.MailScanner;

import javax.sql.DataSource;
import javax.swing.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Main {
    private static Logger logger = Logger.getLogger(MainWindow.class.getName());

    private static MainForm mainForm;

    /**
     * @param args
     */
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });

        // start DB synchronizer
        try {
            @SuppressWarnings({"HardCodedStringLiteral"})
            Folder2DBSynchronizer synchronizer = (Folder2DBSynchronizer) Context.getBeanFactory().getBean("folder2DBSynchronizer");

            synchronizer.setItems(readElements(Folder2DBItems.class, Parameters.getFolder2DBFileName()));
            synchronizer.startDaemon();
        } catch (JAXBException jae) {
            logger.log(Level.SEVERE, "Can not read XML file", jae);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Can not read XML file", e);
        }

    }

    protected static void createAndShowGUI() {
        List<MailScanner> mailScanners = (List<MailScanner>) Context.getBeanFactory().getBean("mailScanners");
        for (MailScanner mailScanner : mailScanners) {
            mailScanner.startScanning();
        }

        JFrame frame = new JFrame("Управление файлами и папками");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        mainForm = new MainForm();
        frame.setContentPane(mainForm.panel1);

        try {
            Explorers explorers = readElements(Explorers.class, Parameters.getExplorersFileName());
            ExplorerPanelBuilder explorerPanelBuilder = (ExplorerPanelBuilder) Context.getBeanFactory().getBean("explorerPanelBuilder");
            File explorersFolder = new File(Parameters.getQueriesFileName()).getParentFile();
            for (Explorer explorer : explorers.getExplorers()) {
                JPanel panel = new JPanel();

                Icon icon = Util.loadIcon(explorersFolder, explorer.getIcon());
                mainForm.tabbedPane1.addTab(explorer.getTitle(), icon, panel);
                panel.setLayout(new GridLayout(1, 1));
                explorerPanelBuilder.createContent(panel, explorer);
            }
        } catch (JAXBException e) {
            logger.log(Level.SEVERE, "Cannot add explorers", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Cannot add explorers", e);
        }

        frame.setJMenuBar(createMenuBar());

        final File baseFolder = (File) Context.getBeanFactory().getBean("baseFolder");
        final ExtendedFileSystemModel model = new ExtendedFileSystemModel(baseFolder);

        /*
        mainForm.treeTable = new JXTreeTable();

        final EventDispatcher eventDispatcher = (EventDispatcher) Context.getBeanFactory().getBean("eventDispatcher");
        eventDispatcher.addEventListener(UIEvent.REFRESH, new IEventListener() {
            @Override
            public void handleEvent(IEvent event) {
                if (mainForm.treeTable.isShowing()) {
                    model.refresh();
                }
            }
        });

        mainForm.treeTable.setTreeTableModel(model);
        mainForm.leftPanel.setLayout(new GridLayout(1,1));
        JScrollPane scrollPane = new JScrollPane(mainForm.treeTable);
//        mainForm.treeTable.getTableHeader().setVisible(true);
        mainForm.leftPanel.add(scrollPane);
        //*/

        try {
            QueriesMD queries = readElements(QueriesMD.class, Parameters.getQueriesFileName());
            File queryFolder = new File(Parameters.getQueriesFileName()).getParentFile();
            for (final QueryMD query : queries) {
                final JPanel panel = new JPanel();
                Icon icon = Util.loadIcon(queryFolder, query.getIcon());
                mainForm.tabbedPane1.addTab(query.getName(), icon, panel);
                panel.setLayout(new GridLayout(1, 1));
                final GridFactory gridFactory = (GridFactory) Context.getBeanFactory().getBean("gridFactory");
                ComponentListener componentListener = new ComponentAdapter() {
                    boolean shown = false;


                    @Override
                    public void componentShown(ComponentEvent componentEvent) {
                        if (!shown) {
                            gridFactory.createContent(panel, query);
                            panel.updateUI();
                            shown = true;
                        }
                    }
                };
                // componentListener.componentShown(null);
                panel.addComponentListener(componentListener);
            }

        } catch (JAXBException e) {
            logger.log(Level.SEVERE, "Error loading XML files", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Error loading XML files", e);
        }


        // frame.setContentPane(mainWindow.createContentPane());

        //Display the window.
        frame.setSize(800, 600);
        frame.setVisible(true);
        startFolderScanner();
    }


    public static JMenuBar createMenuBar() {
        final JMenuBar menuBar = new JMenuBar();
        final EventDispatcher eventDispatcher = (EventDispatcher) Context.getBeanFactory().getBean("eventDispatcher");
        JMenu menu = new JMenu("Создать");

        try {
            ActionsMD actions = readElements(ActionsMD.class, Parameters.getActionsFileName());

            for (final ActionMD action : actions) {
                JMenuItem menuItem = new JMenuItem(action.getName());
                menu.add(menuItem);
                menuItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        performAction(action, null, null);
                    }
                });

                if (action.getTable() != null) {
                    IEventListener listener = new IEventListener() {
                        @Override
                        public void handleEvent(IEvent event) {
                            if (event instanceof EditEvent) {
                                EditEvent editEvent = (EditEvent) event;
                                if (editEvent.getEntityName().equals(action.getTable())) {
                                    performAction(action, null, editEvent.getEntityId());
                                }
                            }
                        }
                    };
                    eventDispatcher.addEventListener(EditEvent.ID, listener);
                }
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error creating menu", e);
        }

        menuBar.add(menu);

        menu = new JMenu("Вид");
        final JMenuItem menuItem = new JMenuItem("Обновить", KeyEvent.VK_F5);
        menuItem.setMnemonic(KeyEvent.VK_F5);
        KeyStroke keyStroke = KeyStroke.getKeyStroke("F5");
        menuItem.setAccelerator(keyStroke);
        menu.add(menuItem);
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                eventDispatcher.sendEvent(new UIEvent(UIEvent.REFRESH));
//
//                if(refreshHandler != null)
//                    refreshHandler.run();
            }
        });

        menuBar.add(menu);

        return menuBar;
    }

    protected static void performAction(final ActionMD action, final File[] filesToCopy, Object entityId) {
        final File baseFolder = (File) Context.getBeanFactory().getBean("baseFolder");
        final DataSource dataSource = (DataSource) Context.getBeanFactory().getBean("dataSource");

        ValueObject valueObjectTmp;

        if (entityId != null) {
            valueObjectTmp = Util.populateObject(action, entityId, dataSource);

        } else {
            valueObjectTmp = new ValueObject();
            Initializer initializer = (Initializer) Context.getBeanFactory().getBean("actionInitializer");
            initializer.init(action, valueObjectTmp);
        }
        final ValueObject valueObject = valueObjectTmp;

        ActionParamDlg paramDlg = new ActionParamDlg(action, valueObject) {
            @Override
            protected void onOK() {
                super.onOK();
                ActionProcessor.processAction(action, valueObject, baseFolder, dataSource, filesToCopy);
                EventDispatcher eventDispatcher = (EventDispatcher) Context.getBeanFactory().getBean("eventDispatcher");
                eventDispatcher.sendEvent(new UIEvent(UIEvent.REFRESH));
            }
        };
        paramDlg.pack();
        Dimension size = paramDlg.getSize();
        paramDlg.setSize(size.width + 50, size.height);
        paramDlg.setLocationRelativeTo(mainForm.panel1);

        paramDlg.setVisible(true);

    }

    protected static <T> T readElements(Class<T> cls, String fileName) throws JAXBException, IOException {
        JAXBContext context = JAXBContext.newInstance(cls);
        FileInputStream fis = new FileInputStream(fileName);
        Unmarshaller um = context.createUnmarshaller();
        T res = (T) um.unmarshal(fis);
        return res;
    }

    private static FolderChangedDlg dlg = new FolderChangedDlg();

    protected static void startFolderScanner() {
        FolderScanner folderScanner = (FolderScanner) Context.getBeanFactory().getBean("folderScanner");

        try {
            ActionsMD actions = readElements(ActionsMD.class, Parameters.getActionsFileName());
            List<ActionMD> fileActions = new ArrayList<ActionMD>();
            for (ActionMD action : actions) {
                if (action.isFileAction()) {
                    fileActions.add(action);
                }
            }

            dlg.setAtions(fileActions);

        } catch (JAXBException e) {
            logger.log(Level.SEVERE, "Error starting folder scanner", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Error starting folder scanner", e);
        }

        FolderChangedListener listener = new FolderChangedListener() {
            @Override
            public void folderChanged(final File[] newFiles) {

                javax.swing.SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        dlg.addFiles(newFiles);
                        if (!dlg.isVisible())
                            dlg.pack();
                        dlg.setModal(true);
                        dlg.toFront();
                        dlg.setVisible(true);
                        File files[] = dlg.getSelectedFiles();
                        ActionMD seleActionMD = dlg.getSelectedAction();
                        performAction(seleActionMD, files, null);
                    }
                });
            }
        };
        folderScanner.addChangeListener(listener);

        folderScanner.start();
    }
}
